package com.dingreading.cloud.soms.service.impl;

import com.dingreading.cloud.common.util.*;
import com.dingreading.cloud.soms.dto.CmServiceCountDto;
import com.dingreading.cloud.soms.dto.CmservicesDto;
import com.dingreading.cloud.soms.dto.LeftLessonDto;
import com.dingreading.cloud.soms.dto.SimpleCmserviceDto;
import com.dingreading.cloud.soms.entity.Cmservices;
import com.dingreading.cloud.soms.entity.table.CmservicesTableDef;
import com.dingreading.cloud.soms.mapper.CmservicesMapper;
import com.dingreading.cloud.soms.mapper.MembersMapper;
import com.dingreading.cloud.soms.service.CmservicesService;
import com.dingreading.cloud.soms.util.ScheduleUtil;
import com.google.common.collect.Lists;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.*;
import com.mybatisflex.core.update.UpdateChain;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.ParseException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.dingreading.cloud.soms.entity.table.CmordersTableDef.cmorders;
import static com.dingreading.cloud.soms.entity.table.MembersTableDef.members;
import static com.dingreading.cloud.soms.entity.table.StoreProjectsTableDef.storeProjects;


/**
 * 服务层实现。
 *
 * @author Administrator
 * @since 2023-11-22
 */
@Service
public class CmservicesServiceImpl extends BaseServiceImpl<CmservicesMapper, Cmservices, CmservicesTableDef> implements CmservicesService {

    @Resource
    private MembersMapper membersMapper;

    @Override
    protected CmservicesTableDef getTable() {
        return CmservicesTableDef.cmservices;
    }

    // 服务开卡的三种状态
    private final List<Integer> cardStatusList = Lists.newArrayList(
            EnumType.ServiceStatus.NO_CARD.getStatus(),
            EnumType.ServiceStatus.OPEN_CARD.getStatus(),
            EnumType.ServiceStatus.PAUSE_CARD.getStatus()
    );

    @Override
    public Page<CmservicesDto> pageList(PageUtil pageUtil, String storeUid, String memberUid, String keyword) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));
        if (StringUtils.isNotBlank(memberUid))
            condition.and(table.memberUid.eq(memberUid));
        if (StringUtils.isNotBlank(keyword))
            condition.and(table.productName.like(keyword));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.desc());

        return getMapper().paginateAs(Page.of(pageUtil.getPage(), pageUtil.getRows()), wrapper, CmservicesDto.class);
    }

    @Override
    public Page<CmservicesDto> storePage(
            PageUtil pageUtil, String storeUid, String keyword, String beginDate, String endDate,
            Integer status, Integer type, Integer gift
    ) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid));
        if (StringUtils.isNotBlank(keyword))
            condition.and(table.productName.like(keyword)
                    .or(members.memberName.like(keyword))
                    .or(table.orderCode.like(keyword)));

        if (null != gift)
            condition.and(table.isGift.eq(gift));

        QueryOrderBy queryOrderBy = table.id.desc();
        // 查询类型 1.即将过期 2.已过期 3.活动次数不足 4.剩余活动次数
        if (null != type) {
            condition.and(table.status.in(cardStatusList))
                    .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()));
            if (type.equals(1)) {
                // 即将过期（三个月）
                Date bDate = new Date();
                Date eDate = DateUtil.addMonths(bDate, 2);
                try {
                    String bgn = DateUtil.getDefaultBGNTimeStr(bDate);
                    bDate = DateUtil.parseDayBeginFromStr(bgn);

                    String end = DateUtil.getDefaultLastTimeStr(eDate);
                    eDate = DateUtil.parseDayEndFromStr(end);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                condition.and(table.endDate.between(bDate, eDate));
                queryOrderBy = table.endDate.asc();
            } else if (type.equals(2)) {
                // 已过期
                Date date = new Date();
                try {
                    String bgn = DateUtil.getDefaultBGNTimeStr(date);
                    date = DateUtil.parseDayBeginFromStr(bgn);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                condition.and(table.freeStatus.eq(0))
                        .and(table.endDate.isNotNull())
                        .and(table.endDate.lt(date));
                queryOrderBy = table.endDate.desc();
            } else if (type.equals(3)) {
                // 活动次数不足
                condition.and(table.leftLessons.isNotNull())
                        .and(table.leftLessons.le(8))
                        .and(table.lessonStatus.eq(1))
                        .and(table.freeStatus.eq(1))
                        .and(table.status.in(EnumType.ServiceStatus.PAUSE_CARD.getStatus(), EnumType.ServiceStatus.OPEN_CARD.getStatus()))
                        .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
                        .and(table.ending.eq(0));
                queryOrderBy = table.leftLessons.desc();
            } else if (type.equals(4)) {
                // 剩余活动次数
                condition.and(table.leftLessons.isNotNull())
                        .and(table.leftLessons.gt(0))
                        .and(table.lessonStatus.eq(1))
                        .and(table.freeStatus.eq(1))
                        .and(table.status.in(cardStatusList))
                        .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
                        .and(table.ending.eq(0));
                queryOrderBy = table.leftLessons.desc();
            }
        } else {
            if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate))
                condition.and(table.addTime.between(QueryFiledUtil.appendMin00(beginDate), QueryFiledUtil.appendMin24(endDate)));

            if (status != null) {
                if (cardStatusList.contains(status)) {
                    condition.and(table.status.eq(status))
                            .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()));
                } else {
                    condition.and(table.changeStatus.eq(status));
                }
            }
        }

        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.allColumns, members.memberName.as("newMemberName"))
                .from(table)
                .leftJoin(members).on(table.memberUid.eq(members.uid))
                .where(condition)
                .orderBy(queryOrderBy);

        return getMapper().paginateAs(Page.of(pageUtil.getPage(), pageUtil.getRows()), wrapper, CmservicesDto.class);
    }

    @Override
    public void dropByOrderCode(String storeUid, String memberUid, String orderCode) {
        QueryCondition condition = table.orderCode.eq(orderCode)
                .and(table.storeUid.eq(storeUid))
                .and(table.memberUid.eq(memberUid))
                .and(table.status.eq(-1))
                .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
                .and(table.ending.eq(0));
        getMapper().deleteByCondition(condition);
    }

    @Override
    public void dropByOrderCodeAndUidNot(
            String storeUid, String memberUid, String orderCode, List<String> serviceUids
    ) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.memberUid.eq(memberUid))
                .and(table.orderCode.eq(orderCode))
                .and(table.status.eq(-1))
                .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
                .and(table.ending.eq(0));
        if (CollectionUtils.isNotEmpty(serviceUids))
            condition.and(table.uid.notIn(serviceUids));
        getMapper().deleteByCondition(condition);
    }

    @Override
    public void updateList(String storeUid, String memberUid, String orderCode, String orderType, List<String> uids, String staffUid, String staffName) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.memberUid.eq(memberUid))
                .and(table.orderCode.eq(orderCode))
                .and(table.uid.in(uids));
        UpdateChain.of(Cmservices.class)
                .set(table.orderType, orderType)
                .set(table.lastStaffUid, NepUtil.nullToZero(staffUid))
                .set(table.lastStaffName, NepUtil.nullToZero(staffName))
                .set(table.lastEditTime, DateUtil.getNowDatetime())
                .where(condition)
                .update();
    }

    @Override
    public List<CmservicesDto> dtoListByOrderCodeAndStatusIn(String storeUid, String memberUid, String orderCode) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.memberUid.eq(memberUid))
                .and(table.orderCode.eq(orderCode))
                .and(table.status.in(cardStatusList));
        QueryWrapper where = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.desc());

        return getMapper().selectListByQueryAs(where, CmservicesDto.class);
    }

    @Override
    public List<CmservicesDto> dtoListByOrderCodeOrRelationCode(String storeUid, String orderCode) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.orderCode.eq(orderCode).or(table.relationCode.eq(orderCode)));
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));
//        QueryWrapper wrapper = QueryWrapper.create()
//                .where(condition)
//                .orderBy(table.id.desc());
        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.allColumns, members.memberName.as("newMemberName"))
                .from(table)
                .leftJoin(members).on(table.memberUid.eq(members.uid))
                .where(condition);
        return getMapper().selectListByQueryAs(wrapper, CmservicesDto.class);
    }

    @Override
    public List<CmservicesDto> dtoListByOrderCodesAndStatusIn(String storeUid, List<String> orderCodes) {
        QueryCondition condition = table.orderCode.in(orderCodes)
                .and(table.status.in(cardStatusList));
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));
        QueryWrapper where = QueryWrapper.create()
                .where(condition);
        return getMapper().selectListByQueryAs(where, CmservicesDto.class);
    }

    @Override
    public List<SimpleCmserviceDto> simpleDtoListByOrderCodesAndStatusIn(String storeUid, List<String> orderCodes) {
        QueryCondition condition = table.orderCode.in(orderCodes)
                .and(table.status.in(cardStatusList));
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));
        QueryWrapper where = QueryWrapper.create()
                .where(condition);
        return getMapper().selectListByQueryAs(where, SimpleCmserviceDto.class);
    }

    @Override
    public CmservicesDto dtoByUid(String storeUid, String memberUid, String orderCode, String uid) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.memberUid.eq(memberUid))
                .and(table.orderCode.eq(orderCode))
                .and(table.uid.eq(uid));
        QueryWrapper where = QueryWrapper.create()
                .where(condition);
        return getMapper().selectOneByQueryAs(where, CmservicesDto.class);
    }

    @Override
    public Cmservices getByUid(String storeUid, String orderCode, String uid) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.orderCode.eq(orderCode))
                .and(table.uid.eq(uid));
        return getMapper().selectOneByCondition(condition);
    }

    @Override
    public boolean updateInfo(
            String storeUid, String orderCode, String serviceUid, String lastStaffUid, String lastStaffName,
            String staffUid, String staffFullName, String staffNickName,
            String staffPriPhone, String remarks
    ) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.orderCode.eq(orderCode))
                .and(table.uid.eq(serviceUid));

        return UpdateChain.of(Cmservices.class)
                .set(table.staffUid, staffUid)
                .set(table.staffFullName, NepUtil.nullToZero(staffFullName))
                .set(table.staffNickName, NepUtil.nullToZero(staffNickName))
                .set(table.staffPriPhone, NepUtil.nullToZero(staffPriPhone))
                .set(table.lastStaffUid, NepUtil.nullToZero(lastStaffUid))
                .set(table.lastStaffName, NepUtil.nullToZero(lastStaffName))
                .set(table.lastEditTime, DateUtil.getNowDatetime())
                .set(table.remarks, remarks)
                .where(condition)
                .update();
    }

    @Override
    public boolean setStatusV3(
            String storeUid, String orderCode, String serviceUid, String lastStaffUid, String lastStaffName,
            Date beginDate, Date endDate, Date pauseDate, int status, String statusName
    ) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.orderCode.eq(orderCode))
                .and(table.uid.eq(serviceUid))
                .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
                .and(table.ending.eq(0));
        if (status == 1) {
            // 未开卡或暂停服务，可以开卡
            condition.and(table.status.eq(EnumType.ServiceStatus.NO_CARD.getStatus()).or(table.status.eq(EnumType.ServiceStatus.PAUSE_CARD.getStatus())));
        } else if (status == 0) {
            // 已开卡，可以暂停
            condition.and(table.status.eq(EnumType.ServiceStatus.OPEN_CARD.getStatus()));
        } else if (status == 2) {
            // 已暂停，可以继续服务
            condition.and(table.status.eq(EnumType.ServiceStatus.PAUSE_CARD.getStatus()));
        }

        UpdateChain<Cmservices> update = UpdateChain.of(Cmservices.class);
        if (null != beginDate) {
            update.set(table.beginDate, beginDate)
                    .set(table.changeDate, beginDate);
        }
        if (null != endDate) {
            update.set(table.endDate, endDate);
        }
        if (null != pauseDate)
            update.set(table.pauseDate, pauseDate);
        update.set(table.status, status)
                .set(table.statusName, statusName)
                .set(table.lastStaffUid, NepUtil.nullToZero(lastStaffUid))
                .set(table.lastStaffName, NepUtil.nullToZero(lastStaffName))
                .set(table.lastEditTime, DateUtil.getNowDatetime());
        return update.where(condition).update();
    }

    @Override
    public boolean haveOpenCard(String orderCode) {
        // 状态 未开通:-1，暂停服务:0，服务中:1
        QueryCondition condition = table.orderCode.eq(orderCode)
                .and(table.status.in(EnumType.ServiceStatus.PAUSE_CARD.getStatus(), EnumType.ServiceStatus.OPEN_CARD.getStatus()));
        return exists(condition);
    }

    @Override
    public Map<String, LeftLessonDto> getLeftLessonCntV2(String storeUid, String projectUid, List<String> memberUids) {
        List<LeftLessonDto> list = membersMapper.serviceMemberByMemberUidList(storeUid, memberUids, projectUid, ScheduleUtil.TIYAN_UID);
        Map<String, LeftLessonDto> map = new HashMap<>();
        if (CollectionUtils.isNotEmpty(list))
            map = list.stream().collect(Collectors.toMap(LeftLessonDto::getMemberUid, Function.identity()));
        return map;
    }

    @Override
    public Cmservices getMemberConsumesService(String storeUid, String memberUid, String projectUid) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.projectUid.eq(projectUid).or(table.projectUid.eq(ScheduleUtil.TIYAN_UID)))
                .and(table.memberUid.eq(memberUid))
                .and(table.leftLessons.gt(0))
                .and(table.lessonStatus.eq(1))
                .and(table.status.in(EnumType.ServiceStatus.PAUSE_CARD.getStatus(), EnumType.ServiceStatus.OPEN_CARD.getStatus()))
                .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
                .and(table.ending.eq(0));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                // 订单号时间最早优先、非赠送优先、非体验课服务优先
                .orderBy(table.orderCode.asc(), table.isGift.asc(), QueryMethods.field(table.projectUid, QueryMethods.string(ScheduleUtil.TIYAN_UID)).asc());
        return getMapper().selectOneByQuery(wrapper);
    }

    @Override
    public Cmservices getMemberConsumesNoCardService(String storeUid, String memberUid, String projectUid) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.projectUid.eq(projectUid))
                .and(table.memberUid.eq(memberUid))
                .and(table.leftLessons.gt(0))
                .and(table.lessonStatus.eq(1))
                .and(table.status.in(EnumType.ServiceStatus.NO_CARD.getStatus()))
                .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
                .and(table.ending.eq(0))
                .and(storeProjects.isPay.eq(0));

        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.allColumns)
                .from(table)
                .leftJoin(storeProjects).on(table.projectUid.eq(storeProjects.uid))
                .where(condition)
                // 订单号时间最早优先、非赠送优先
                .orderBy(table.orderCode.asc(), table.isGift.asc());
        List<Cmservices> list = getMapper().selectListByQuery(wrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public boolean updateLeftLesson(String corpUid, String storeUid, String memberUid, String uid) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.corpUid.eq(corpUid))
                .and(table.storeUid.eq(storeUid))
                .and(table.memberUid.eq(memberUid))
                .and(table.uid.eq(uid))
                .and(table.leftLessons.gt(0))
                .and(table.lessonStatus.eq(1))
                .and(table.status.in(EnumType.ServiceStatus.PAUSE_CARD.getStatus(), EnumType.ServiceStatus.OPEN_CARD.getStatus()))
                .and(table.ending.eq(0));
        return UpdateChain.of(Cmservices.class)
                .set(table.leftLessons, table.leftLessons.subtract(1))
                .where(condition)
                .update();
    }

    @Override
    public boolean updateChangeStatusByUidList(
            List<String> uidList, String memberUid, String orderCode, String staffUid, String staffName,
            String relationCode, Date changeDate, Integer changeStatus, String changeStatusName
    ) {
        QueryCondition condition = table.memberUid.eq(memberUid)
                .and(table.orderCode.eq(orderCode))
                .and(table.uid.in(uidList))
                .and(table.status.in(cardStatusList))
                .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
                .and(table.ending.eq(0));

        return UpdateChain.of(Cmservices.class)
                .set(table.changeDate, changeDate)
                .set(table.changeStatus, changeStatus)
                .set(table.changeStatusName, changeStatusName)
                .set(table.ending, 1)
                .set(table.endingType, 2)
                .set(table.relationCode, relationCode)
                .set(table.lastStaffUid, NepUtil.nullToZero(staffUid))
                .set(table.lastStaffName, NepUtil.nullToZero(staffName))
                .set(table.lastEditTime, DateUtil.getNowDatetime())
                .where(condition)
                .update();
    }

    @Override
    public boolean existOpenServices(String storeUid, String memberUid, String orderCode, List<String> serviceUids) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.memberUid.eq(memberUid))
                .and(table.orderCode.eq(orderCode))
                .and(table.status.in(EnumType.ServiceStatus.PAUSE_CARD.getStatus(), EnumType.ServiceStatus.OPEN_CARD.getStatus()))
                .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()));
        if (CollectionUtils.isNotEmpty(serviceUids))
            condition.and(table.uid.notIn(serviceUids));
        return exists(condition);
    }

    @Override
    public boolean haveProjectUid(String storeUid, String projectUid) {
        QueryCondition condition = table.projectUid.eq(projectUid);
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));
        return exists(condition);
    }

    @Override
    public boolean haveProductUid(String storeUid, String productUid) {
        QueryCondition condition = table.productUid.eq(productUid);
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));
        return exists(condition);
    }

    @Override
    public List<Cmservices> listByStoreUidAndMemberUidAndUidIn(String storeUid, String memberUid, List<String> serviceUidList) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.memberUid.eq(memberUid))
                .and(table.uid.in(serviceUidList));
        return getMapper().selectListByCondition(condition);
    }

    @Override
    public List<CmservicesDto> getTransferServices(String storeUid, String memberUid) {
        QueryCondition condition = QueryCondition.createEmpty();
        try {
            Date nowDate = DateUtil.parseDateFromStr(QueryFiledUtil.appendMin24(DateUtil.getNowDateStr()));
            int openCardStatus = EnumType.ServiceStatus.OPEN_CARD.getStatus();
            int noCardStatus = EnumType.ServiceStatus.NO_CARD.getStatus();
            int pauseCardStatus = EnumType.ServiceStatus.PAUSE_CARD.getStatus();
            int noChangeStatus = EnumType.ServiceStatus.NO_CHANGE.getStatus();

            condition.and(table.storeUid.eq(storeUid))
                    .and(table.memberUid.eq(memberUid))
                    .and(table.changeStatus.eq(noChangeStatus))
                    .and(table.ending.eq(0));
            condition.and(table.status.eq(noCardStatus)
                    .or(table.status.in(pauseCardStatus, openCardStatus)
                            .and(table.lessonStatus.eq(1).and(table.leftLessons.gt(0))
                                    .or(table.lessonStatus.eq(0).and(table.endDate.gt(nowDate)))))
            );
        } catch (ParseException e) {
            e.printStackTrace();
        }

        QueryWrapper where = QueryWrapper.create().where(condition);

        return getMapper().selectListByQueryAs(where, CmservicesDto.class);
    }

    @Override
    public boolean updateStoreInfo(String storeUid, String memberUid, String toStoreUid, String toStoreName, List<String> uids) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.memberUid.eq(memberUid))
                .and(table.uid.in(uids));
        return UpdateChain.of(Cmservices.class)
                .set(table.storeUid, toStoreUid)
                .set(table.storeName, toStoreName)
                .where(condition)
                .update();
    }

    @Override
    public List<Cmservices> listByOrderCodeAndType(String orderCode, boolean editOrder) {
        QueryCondition condition = table.orderCode.eq(orderCode);
        // 1:创建、更新、变更、退费使用，0:补充数据使用
        if (editOrder)
            condition.and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()));
        else
            condition.and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus())
                    .or(table.changeStatus.eq(EnumType.ServiceStatus.INVALID.getStatus()))
            );
        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition);
        return getMapper().selectListByQuery(wrapper);
    }

    @Override
    public void updateAmount(String uid, double totalAmount, double unitAmount) {
        UpdateChain.of(Cmservices.class)
                .set(table.totalAmount, totalAmount)
                .set(table.unitAmount, unitAmount)
                .where(table.uid.eq(uid))
                .update();
    }

    @Override
    public List<CmservicesDto> exportList(String storeUid, String keyword, String beginDate, String endDate, Integer status, Integer type, Integer gift) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid));
        if (StringUtils.isNotBlank(keyword))
            condition.and(table.productName.like(keyword)
                    .or(table.memberName.like(keyword))
                    .or(table.orderCode.like(keyword)));

        if (null != gift)
            condition.and(table.isGift.eq(gift));

        QueryOrderBy queryOrderBy = table.id.desc();
        // 查询类型 1.即将过期 2.已过期 3.活动次数不足
        if (null != type) {
            condition.and(table.status.in(cardStatusList))
                    .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()));
            if (type.equals(1)) {
                // 即将过期（三个月）
                Date bDate = new Date();
                Date eDate = DateUtil.addMonths(bDate, 2);
                try {
                    String bgn = DateUtil.getDefaultBGNTimeStr(bDate);
                    bDate = DateUtil.parseDayBeginFromStr(bgn);

                    String end = DateUtil.getDefaultLastTimeStr(eDate);
                    eDate = DateUtil.parseDayEndFromStr(end);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                condition.and(table.endDate.between(bDate, eDate));
                queryOrderBy = table.endDate.asc();
            } else if (type.equals(2)) {
                // 已过期
                Date date = new Date();
                try {
                    String bgn = DateUtil.getDefaultBGNTimeStr(date);
                    date = DateUtil.parseDayBeginFromStr(bgn);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                condition.and(table.freeStatus.eq(0))
                        .and(table.endDate.isNotNull())
                        .and(table.endDate.lt(date));
                queryOrderBy = table.endDate.desc();
            } else if (type.equals(3)) {
                // 活动次数不足
                condition.and(table.leftLessons.isNotNull())
                        .and(table.leftLessons.le(8))
                        .and(table.lessonStatus.eq(1))
                        .and(table.freeStatus.eq(1))
                        .and(table.status.in(EnumType.ServiceStatus.PAUSE_CARD.getStatus(), EnumType.ServiceStatus.OPEN_CARD.getStatus()))
                        .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
                        .and(table.ending.eq(0));
                queryOrderBy = table.leftLessons.desc();
            } else if (type.equals(4)) {
                // 活动次数不足
                condition.and(table.leftLessons.isNotNull())
                        .and(table.leftLessons.gt(0))
                        .and(table.lessonStatus.eq(1))
                        .and(table.freeStatus.eq(1))
                        .and(table.status.in(cardStatusList))
                        .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
                        .and(table.ending.eq(0));
                queryOrderBy = table.leftLessons.desc();
            }
        } else {
            if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate))
                condition.and(table.addTime.between(QueryFiledUtil.appendMin00(beginDate), QueryFiledUtil.appendMin24(endDate)));

            if (status != null) {
                if (cardStatusList.contains(status)) {
                    condition.and(table.status.eq(status))
                            .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()));
                } else {
                    condition.and(table.changeStatus.eq(status));
                }
            }
        }

        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.allColumns, cmorders.orderDate)
                .from(table)
                .leftJoin(cmorders).on(table.orderCode.eq(cmorders.orderCode))
                .where(condition)
                .orderBy(queryOrderBy);

        return getMapper().selectListByQueryAs(wrapper, CmservicesDto.class);
    }

    @Override
    public List<Cmservices> listByOrderCodeAndChangStatusIsNullAndEnding(String storeUid, String memberUid, String orderCode) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.memberUid.eq(memberUid))
                .and(table.orderCode.eq(orderCode))
                .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
                .and(table.ending.eq(0));
        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.asc());
        return getMapper().selectListByQuery(wrapper);
    }

    @Override
    public List<Cmservices> listByOrderCodeAndChangStatusIsNull(String storeUid, String memberUid, String orderCode) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.memberUid.eq(memberUid))
                .and(table.orderCode.eq(orderCode))
                .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()));
        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.asc());
        return getMapper().selectListByQuery(wrapper);
    }

    @Override
    public boolean setFinish(String storeUid, String orderCode, String uid, String endingRemark, String staffUid, String staffName) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.orderCode.eq(orderCode))
                .and(table.uid.eq(uid))
                .and(table.ending.eq(0))
                .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()));

        Date time = DateUtil.getNowDatetime();
        return UpdateChain.of(Cmservices.class)
                .set(table.ending, 1)
                .set(table.endingType, 3)
                .set(table.endingTime, time)
                .set(table.endingRemark, endingRemark)
                .set(table.endingStaffUid, NepUtil.nullToZero(staffUid))
                .set(table.endingStaffName, NepUtil.nullToZero(staffName))
                .set(table.lastStaffUid, NepUtil.nullToZero(staffUid))
                .set(table.lastStaffName, NepUtil.nullToZero(staffName))
                .set(table.lastEditTime, time)
                .where(condition)
                .update();
    }

    @Override
    public boolean setRecover(String storeUid, String orderCode, String uid, String staffUid, String staffName) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.orderCode.eq(orderCode))
                .and(table.uid.eq(uid))
                .and(table.ending.eq(1))
                .and(table.endingType.eq(3))
                .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()));

        return UpdateChain.of(Cmservices.class)
                .set(table.ending, 0)
                .set(table.endingType, 0)
                .set(table.endingTime, null)
                .set(table.endingRemark, "")
                .set(table.lastStaffUid, NepUtil.nullToZero(staffUid))
                .set(table.lastStaffName, NepUtil.nullToZero(staffName))
                .set(table.lastEditTime, DateUtil.getNowDatetime())
                .where(condition)
                .update();
    }

    @Override
    public Cmservices getMemberConsumesServiceV2(List<String> orderCodeListBy250699List, String storeUid, String memberUid, String projectUid) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.projectUid.eq(projectUid).or(table.projectUid.eq(ScheduleUtil.TIYAN_UID)))
                .and(table.memberUid.eq(memberUid))
                .and(table.leftLessons.gt(0))
                .and(table.lessonStatus.eq(1))
                .and(table.status.in(EnumType.ServiceStatus.PAUSE_CARD.getStatus(), EnumType.ServiceStatus.OPEN_CARD.getStatus()))
                .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
                .and(table.ending.eq(0))
                .and(table.orderCode.in(orderCodeListBy250699List))
        ;

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                // 订单号时间最早优先、非赠送优先、非体验课服务优先
                .orderBy(table.orderCode.asc(), table.isGift.asc(), QueryMethods.field(table.projectUid, QueryMethods.string(ScheduleUtil.TIYAN_UID)).asc());
        return getMapper().selectOneByQuery(wrapper);
    }

    @Override
    public List<Cmservices> listByOrderCodeIn(List<String> orderCodeList) {
        return getMapper().selectListByCondition(table.orderCode.in(orderCodeList));
    }

    @Override
    public List<CmServiceCountDto> cmserviceCountList(String storeUid, List<String> orderCodeList) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.orderCode.in(orderCodeList))
                .and(table.changeStatus.in(EnumType.ServiceStatus.NO_CHANGE.getStatus()));
        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.uid, table.memberUid, table.orderType, table.orderCode, table.status,
                        table.productName, table.leftLessons, table.lessonStatus, table.ending, members.customSource
                )
                .from(table)
                .leftJoin(members).on(table.memberUid.eq(members.uid))
                .where(condition);
        return getMapper().selectListByQueryAs(wrapper, CmServiceCountDto.class);
    }

    @Override
    public List<CmServiceCountDto> shouldRenewList(String storeUid, String beginDate, String endDate) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.orderType.in(EnumType.OrderType.NEW.getType(), EnumType.OrderType.EXT.getType()))
                .and(table.changeStatus.in(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
                .and(table.lessonStatus.eq(1).and(table.leftLessons.le(4)).and(members.grade.lt(6)).and(table.ending.eq(0))
                        .or(table.ending.eq(1).and(table.endingTime.between(QueryFiledUtil.appendMin00(beginDate), QueryFiledUtil.appendMin24(endDate))))
                );
        QueryWrapper wrapper = QueryWrapper.create()
                .select(getCmServiceCountDto())
                .from(table)
                .leftJoin(members).on(table.memberUid.eq(members.uid))
                .where(condition);
        return getMapper().selectListByQueryAs(wrapper, CmServiceCountDto.class);
    }

    @Override
    public List<CmServiceCountDto> endingList(String storeUid, String beginDate, String endDate) {
        QueryCondition condition = table.storeUid.eq(storeUid)
                .and(table.endingTime.between(QueryFiledUtil.appendMin00(beginDate), QueryFiledUtil.appendMin24(endDate)))
                .and(table.ending.eq(1))
                .and(table.orderType.notIn(EnumType.OrderType.EXP.getType(), EnumType.OrderType.GIFT.getType(), EnumType.OrderType.REFUND.getType()))
                .and(table.changeStatus.in(EnumType.ServiceStatus.NO_CHANGE.getStatus(), EnumType.ServiceStatus.REFUND.getStatus()))
                .and(table.lessonStatus.eq(1));
        QueryWrapper wrapper = QueryWrapper.create()
                .select(getCmServiceCountDto())
                .from(table)
                .where(condition);
        return getMapper().selectListByQueryAs(wrapper, CmServiceCountDto.class);
    }

    private QueryColumn[] getCmServiceCountDto() {
        return new QueryColumn[]{
                table.memberUid, table.orderType, table.orderCode, table.productName
        };
    }

    @Override
    public List<Cmservices> getPushCmservices(String corpUid, String storeUid, String projectUid, List<String> memberUidsForPush) {
        if (CollectionUtils.isEmpty(memberUidsForPush)) {
            return new ArrayList<>();
        }
        QueryCondition condition = QueryCondition.createEmpty()
                .and(table.corpUid.eq(corpUid))
                .and(table.storeUid.eq(storeUid))
                .and(table.projectUid.eq(projectUid))
                .and(table.memberUid.in(memberUidsForPush))
                .and(table.status.eq(EnumType.ServiceStatus.OPEN_CARD.getStatus()))
                .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition);
        return getMapper().selectListByQuery(wrapper);
    }

    @Override
    public boolean setStatusAndActivate(
            String storeUid, String orderCode, String serviceUid, String lastStaffUid, String lastStaffName,
            Date beginDate, Date endDate, int status, String statusName,
            String mainSubjectUid, String mainSubjectName, String subjectUid, String subjectName,
            String stageUid, String stageName, Integer payType, Double activateAmount
    ) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.orderCode.eq(orderCode))
                .and(table.uid.eq(serviceUid))
                .and(table.changeStatus.eq(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
                .and(table.ending.eq(0));
        if (status == 1) {
            // 未开卡或暂停服务，可以开卡
            condition.and(table.status.eq(EnumType.ServiceStatus.NO_CARD.getStatus()).or(table.status.eq(EnumType.ServiceStatus.PAUSE_CARD.getStatus())));
        }

        UpdateChain<Cmservices> update = UpdateChain.of(Cmservices.class);
        if (null != beginDate) {
            update.set(table.beginDate, beginDate)
                    .set(table.changeDate, beginDate);
        }
        if (null != endDate) {
            update.set(table.endDate, endDate);
        }
        update.set(table.status, status)
                .set(table.statusName, statusName)
                .set(table.mainSubjectUid, mainSubjectUid)
                .set(table.mainSubjectName, mainSubjectName)
                .set(table.subjectUid, subjectUid)
                .set(table.subjectName, subjectName)
                .set(table.stageUid, stageUid)
                .set(table.stageName, stageName)
                .set(table.payType, payType)
                .set(table.activateAmount, activateAmount)
                .set(table.lastStaffUid, NepUtil.nullToZero(lastStaffUid))
                .set(table.lastStaffName, NepUtil.nullToZero(lastStaffName))
                .set(table.lastEditTime, DateUtil.getNowDatetime());
        return update.where(condition).update();
    }

    @Override
    public List<String> getStudentsByTeacher(String corpUid, String storeUid, String uid) {
        QueryCondition condition = QueryCondition.createEmpty()
                .and(table.corpUid.eq(corpUid))
                .and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(uid));
        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.memberUid)
                .where(condition);
        return getMapper().selectListByQueryAs(wrapper, String.class).stream().distinct().collect(Collectors.toList());
    }

    @Override
    public List<Cmservices> getByMemberUid(String memberUid) {
        return getMapper().selectListByCondition(table.memberUid.eq(memberUid));
    }


}
